/*
 * load_cpp.c
 *
 *  Created on: 2012/07/31
 *      Author: owner
 */

#include <stdio.h>
#include "sqlite3.h"
#include "db_def.h"
#include "core.h"
#include "Id.h"
#include "../../CCore/parser/cpp/cppdef.h"
#include "../../CCore/parser/coredef.h"
#include "../../CCore/table/core_table.h"

/*TBL_CPPDIRECTIVEINFO*/
static INT loadCppDirectiveInfo(sqlite3 * db, AST transUnitInfo) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;
	U2 macroKind = 0;

	sql_get = sqlite3_mprintf(
			"SELECT * FROM %q WHERE TblUnit=%d ORDER BY TblIndex;",
			TBL_CPPDIRECTIVEINFO, transUnitInfo);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stCoreDirectiveInfoAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, CPP_TABLE_INDEX - 1);

		if (tblIndex != stCoreDirectiveInfoAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		macroKind = sqlite3_column_int(stmt, DIRECTIVE_DIRECTIVE_KIND - 1);
		stCoreDirectiveInfoAccess.kind.set(tblIndex, macroKind);

		switch (macroKind) {
		case CPPDEF_DEF:
		case CPPDEF_UNDEF:
		case CPPDEF_INC:
			stCoreDirectiveInfoAccess.idx_result.set(tblIndex,
					sqlite3_column_int(stmt, DIRECTIVE_RESULT_IDX - 1));
			stCoreDirectiveInfoAccess.str_param.set(tblIndex,
					(PSZ) sqlite3_column_text(stmt, DIRECTIVE_PARAM_STR - 1));
			break;

		case CPPDEF_IF:
		case CPPDEF_ELIF:
			stCoreDirectiveInfoAccess.idx_param.set(tblIndex,
					sqlite3_column_int(stmt, DIRECTIVE_PARAM_IDX - 1));
			stCoreDirectiveInfoAccess.bool_result.set(tblIndex,
					sqlite3_column_int(stmt, DIRECTIVE_RESULT_BOOL - 1));
			break;

		case CPPDEF_ELSE:
			stCoreDirectiveInfoAccess.bool_result.set(tblIndex,
					sqlite3_column_int(stmt, DIRECTIVE_RESULT_BOOL - 1));
			break;

		case CPPDEF_IFDEF:
		case CPPDEF_IFNDEF:
			stCoreDirectiveInfoAccess.str_param.set(tblIndex,
					(PSZ) sqlite3_column_text(stmt, DIRECTIVE_PARAM_STR - 1));
			stCoreDirectiveInfoAccess.bool_result.set(tblIndex,
					sqlite3_column_int(stmt, DIRECTIVE_RESULT_BOOL - 1));
			break;

		case CPPDEF_LINE:
			stCoreDirectiveInfoAccess.s4_param.set(tblIndex,
					sqlite3_column_int(stmt, DIRECTIVE_PARAM_S4 - 1));
			stCoreDirectiveInfoAccess.str_param.set(tblIndex,
					(PSZ) sqlite3_column_text(stmt, DIRECTIVE_PARAM_STR - 1));
			break;

		case CPPDEF_ERROR:
		case CPPDEF_PRAGMA:
			stCoreDirectiveInfoAccess.str_param.set(tblIndex,
					(PSZ) sqlite3_column_text(stmt, DIRECTIVE_PARAM_STR - 1));
			break;

		default:
			break;
		}

		stCoreDirectiveInfoAccess.locScope.set(tblIndex,
				sqlite3_column_int(stmt, DIRECTIVE_CODE_SCOPE - 1));
	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_CPPMACRODEFINFO*/
static INT loadCppMacroDefInfo(sqlite3 * db, AST transUnitInfo) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;

	sql_get = sqlite3_mprintf(
			"SELECT * FROM %q WHERE TblUnit=%d ORDER BY TblIndex;",
			TBL_CPPMACRODEFINFO, transUnitInfo);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stCoreMacroDefInfoAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, CPP_TABLE_INDEX - 1);

		if (tblIndex != stCoreMacroDefInfoAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		stCoreMacroDefInfoAccess.macroKind.set(tblIndex,
				sqlite3_column_int(stmt, MACRODEF_MACRO_KIND - 1));

		stCoreMacroDefInfoAccess.paramNum.set(tblIndex,
				sqlite3_column_int(stmt, MACRODEF_PARAMETER_NUMBER - 1));

		stCoreMacroDefInfoAccess.bValid.set(tblIndex,
				sqlite3_column_int(stmt, MACRODEF_IS_VALID - 1));

		stCoreMacroDefInfoAccess.bVariableParam.set(tblIndex,
				sqlite3_column_int(stmt, MACRODEF_HAS_VARIABLE_PARAMETERS - 1));

		stCoreMacroDefInfoAccess.startReplaceEle.set(tblIndex,
				sqlite3_column_int(stmt, MACRODEF_FIRST_TOKEN_INFO - 1));

		stCoreMacroDefInfoAccess.endReplaceEle.set(tblIndex,
				sqlite3_column_int(stmt, MACRODEF_LAST_TOKEN_INFO - 1));

		stCoreMacroDefInfoAccess.directiveInfo.set(tblIndex,
				sqlite3_column_int(stmt, MACRODEF_DIRECTIVE_INFO - 1));

		stCoreMacroDefInfoAccess.macroName.set(tblIndex,
				(PSZ) sqlite3_column_text(stmt, MACRODEF_MACRO_NAME - 1));

	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_CPPDEFREPINFO*/
static INT loadCppDefRepInfo(sqlite3 * db, AST transUnitInfo) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;

	sql_get = sqlite3_mprintf(
			"SELECT * FROM %q WHERE TblUnit=%d ORDER BY TblIndex;",
			TBL_CPPDEFREPINFO, transUnitInfo);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stCoreDefRepInfoAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, CPP_TABLE_INDEX - 1);

		if (tblIndex != stCoreDefRepInfoAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		stCoreDefRepInfoAccess.index.set(tblIndex,
				sqlite3_column_int(stmt, DEFREP_INDEX_COUNTER - 1));

		stCoreDefRepInfoAccess.kind.set(tblIndex,
				sqlite3_column_int(stmt, DEFREP_PARAM_KIND - 1));

		stCoreDefRepInfoAccess.ppTokenKind.set(tblIndex,
				sqlite3_column_int(stmt, DEFREP_TOKEN_KIND - 1));

		stCoreDefRepInfoAccess.paramIdx.set(tblIndex,
				sqlite3_column_int(stmt, DEFREP_PARAM_INDEX - 1));

		stCoreDefRepInfoAccess.location.set(tblIndex,
				sqlite3_column_int(stmt, DEFREP_CODE_SCOPE_INFO - 1));

		stCoreDefRepInfoAccess.name.set(tblIndex,
				(PSZ) sqlite3_column_text(stmt, DEFREP_TOKEN_LABEL - 1));

	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_CPPPPCONDITION*/
static INT loadCppPPCondition(sqlite3 * db, AST transUnitInfo) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;
	U4 opKind = 0;

	sql_get = sqlite3_mprintf(
			"SELECT * FROM %q WHERE TblUnit=%d ORDER BY TblIndex;",
			TBL_CPPPPCONDITION, transUnitInfo);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stCorePPConditionAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, CPP_TABLE_INDEX - 1);

		if (tblIndex != stCorePPConditionAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		opKind = sqlite3_column_int(stmt, CPPCOND_OPER_KIND - 1);
		stCorePPConditionAccess.OpKind.set(tblIndex, opKind);

		switch (opKind) {
		case xPPTOKEN_DOUBLE:
			stCorePPConditionAccess.dbValue.set(tblIndex,
					sqlite3_column_double(stmt, CPPCOND_VALUEOF_DOUBLE - 1));
			break;

		case xPPTOKEN_ULONG:
			stCorePPConditionAccess.u4Value.set(tblIndex,
					sqlite3_column_int64(stmt,
					CPPCOND_VALUEOF_UNSIGNED - 1));
			break;

		case xPPTOKEN_LONG:
			stCorePPConditionAccess.s4Value.set(tblIndex,
					sqlite3_column_int(stmt, CPPCOND_VALUEOF_SIGNED - 1));
			break;

		default:
			break;
		}

		stCorePPConditionAccess.locScp.set(tblIndex,
				sqlite3_column_int(stmt, CPPCOND_CODE_SCOPE_INFO - 1));

		stCorePPConditionAccess.leftNode.set(tblIndex,
				sqlite3_column_int(stmt, CPPCOND_LEFT_NODE_INFO - 1));

		stCorePPConditionAccess.rightNode.set(tblIndex,
				sqlite3_column_int(stmt, CPPCOND_RIGHT_NODE_INFO - 1));

		stCorePPConditionAccess.nodeKind.set(tblIndex,
				sqlite3_column_int(stmt, CPPCOND_NODE_KIND - 1));

	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_CPPTOKENLIST*/
static INT loadCppTokenList(sqlite3 * db, AST transUnitInfo) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;

	sql_get = sqlite3_mprintf(
			"SELECT * FROM %q WHERE TblUnit=%d ORDER BY TblIndex;",
			TBL_CPPTOKENLIST, transUnitInfo);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stCorePPTokenListAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, CPP_TABLE_INDEX - 1);

		if (tblIndex != stCorePPTokenListAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		stCorePPTokenListAccess.codeScope.set(tblIndex,
				sqlite3_column_int(stmt, CPPTOKEN_CODE_SCOPE_INFO - 1));

		stCorePPTokenListAccess.macroExt.set(tblIndex,
				sqlite3_column_int(stmt, CPPTOKEN_MACRO_EXT - 1));

		stCorePPTokenListAccess.name.set(tblIndex,
				(PSZ) sqlite3_column_text(stmt, CPPTOKEN_TOKEN_LABEL - 1));

		stCorePPTokenListAccess.ppTokenKind.set(tblIndex,
				sqlite3_column_int(stmt, CPPTOKEN_PPTOKEN_KIND - 1));

	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*load cpp all of a unit*/
INT DLL_EXPORT loadUnitCppData(sqlite3 * coreData, AST transUnitInfo) {
	INT rc = 0;

	rc = loadCppDirectiveInfo(coreData, transUnitInfo);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadCppMacroDefInfo(coreData, transUnitInfo);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadCppDefRepInfo(coreData, transUnitInfo);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadCppPPCondition(coreData, transUnitInfo);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadCppTokenList(coreData, transUnitInfo);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	return COEXIT_SUCCESS;
}

VOID DLL_EXPORT clearUnitCpp(VOID) {
	stCoreDirectiveInfoAccess.clear();
	stCoreMacroDefInfoAccess.clear();
	stCoreDefRepInfoAccess.clear();
	stCorePPConditionAccess.clear();
	stCorePPTokenListAccess.clear();
}
